package com.salt.security.wechat.auth;

import com.google.common.collect.Lists;
import com.salt.security.BaseUserDetails;
import com.salt.system.mapper.SysUserMapper;
import com.salt.system.model.domain.SysUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

/**
 * 微信jsCode 身份验证器具体校验实现
 *
 * @author HaiBo Kuang
 * @date 2021/4/20 21:15
 */
@Component
public class JsCodeAuthenticationProvider implements AuthenticationProvider {
    private final Logger logger = LoggerFactory.getLogger("JsCode_Authentication_Provider");
    private SysUserMapper userMapper;

    @Autowired
    public void setJsCodeAuthenticationProvider(SysUserMapper userMapper) {
        this.userMapper = userMapper;
    }

    /**
     * 主体认证方法
     * <p>具体实现。由服务器请求微信api 由jSCode换取用户OpenId由它加载用户</p>
     *
     * @param authentication 认证主体
     * @return 认证结果
     * @throws AuthenticationException 认证异常
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        logger.info("<====jsCode开始认证====>");
        Assert.isInstanceOf(JsCodeAuthenticationToken.class, authentication,
                "当前认证对象不是JsCodeAuthenticationToken！！");
        Object jsCode = authentication.getCredentials();
        Assert.notNull(jsCode, "jsCode不能为空！");
        // 由JSCode验证用户
        logger.info("<===认证的jsCode:{}====>", jsCode);
        logger.info("<==由jsCode换取openId加载用户==>");
        // 具体逻辑 jsCode换取openId需用户自己实现，包括绑定关系表，这里只提供一个思路
        JsCodeAuthenticationToken token = new JsCodeAuthenticationToken(String.valueOf(jsCode));
        token.setOpenId("openId");
        //  判断是微信是否绑定
        token.setWeChatBind(false);
        //设置此次认证 用户基础信息
        token.setUserDetails(getUserDetails());
        return token;
    }

    /**
     * 对验证主体JsCodeAuthenticationToken提供支持
     *
     * @param authentication 验证主体
     * @return 结果
     */
    @Override
    public boolean supports(Class<?> authentication) {
        return (JsCodeAuthenticationToken.class.isAssignableFrom(authentication));
    }

    private BaseUserDetails getUserDetails() {
        SysUser sysUser = new SysUser();
        sysUser.setId(1L);
        return new BaseUserDetails(userMapper.selectOne(sysUser), Lists.newArrayList());
    }
}
